package com.niiwoo.civet.trade.service.local.loan;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.mapper.ProjectBackoutBorrowPrizeMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.user.dto.request.AppButtonDTO;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.enums.MessageTemplateKeyEnum;
import com.niiwoo.civet.user.enums.SMSTemplateKeyEnum;
import com.niiwoo.civet.user.enums.UserLetterTypeEnum;
import com.niiwoo.civet.user.service.SendSmsDubboService;
import com.niiwoo.civet.user.service.UserLetterDubboService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @author wping
 * @Description: 标的退回服务类
 * @date 2018/4/19 19:56
 */
@Slf4j
@Service
public class LoanReturnService {

    public static final String OPERATOR_AUTH_FAIL_RETURN_REASION = "运营商授权失败。";
    public static final String SOCIAL_SECURITY_FAIL_RETURN_REASION = "社保授权失败。";
    public static final String CREDIT_CARD_FAIL_RETURN_REASION = "信用卡授权失败。";
    public static final String TAOBAO_FAIL_RETURN_REASION = "淘宝授权失败。";
    public static final String OTHER_EXCEPTION_RETURN_REASION = "网络信号或服务器繁忙，请联系在线客服或致电客服热线400-0991-888，我们将安排专人为您解决。";

    @Autowired
    private ProjectMapperExt projectMapper;

    @Autowired
    private ProjectBackoutBorrowPrizeMapperExt projectBackoutBorrowPrizeMapperExt;

    @Reference(version = "1.0.0")
    private UserLetterDubboService userLetterDubboService;

    @Reference(version = "1.0.0")
    private SendSmsDubboService sendSmsDubboService;

    @Value("${h5-borrow-detail-url}")
    private String h5BorrowDetailUrl;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String TAOBAO_AUTH_ERROR_MSG_REDIS_KEY = "taobao_auth_error_msg";

    private static final String TAOBAO_AUTH_DEFAULT_ERROR_MSG = "您的淘宝授权失败";

    @Autowired
    private ReturnProjectRecordService returnProjectRecordService;

    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public void returnProject(Long projectId, ProjectSubStatusEnum projectSubStatusEnum, ReturnProjectReasonTypeEnum reasonTypeEnum) {

        if (projectId == null || projectSubStatusEnum == null || reasonTypeEnum == null) {
            log.error("退回标的-失败, projectId/projectSubStatusEnum/reasonTypeEnum非空");
            return;
        }

        String methodName = "退回标的, projectId:" + projectId + ", projectSubStatusEnum:" + projectSubStatusEnum.getDesc() + ", reasonTypeEnum:" + reasonTypeEnum.getDesc();
        Project project = projectMapper.selectByPrimaryKeyForUpdate(projectId);
        if (project == null) {
            log.error(methodName + "-标的不存在");
            return;
        }

        if (!(project.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())
                && project.getSubStatus().equals(ProjectSubStatusEnum.CHECKING_INIT.getSubStatus()))) {
            log.error(methodName + "-标的状态不在审核中, 当前标的状态:{}", project.getSubStatus());
            return;
        }

        //1.更新标的子状态为退回;
        Project project2Update = new Project();
        project2Update.setProjectId(project.getProjectId());
        project2Update.setSubStatus(projectSubStatusEnum.getSubStatus());
        project2Update.setUpdateTime(new Date());
        projectMapper.updateByPrimaryKeySelective(project2Update);

        // 插入贷前退回标的记录
        returnProjectRecordService.insertReturnProjectRecord(projectId, ProjectTypeEnum.getEnum(project.getType()), project.getBorrowUserId(), getReturnReason(reasonTypeEnum), "ProjectSubStatus:" + projectSubStatusEnum.getSubStatus(), getReturnProjectProcessSchemeEnum(reasonTypeEnum));

        //2.异步退回红包;
//        if (project.getPrizeId() != null && project.getPrizeId() > 0) {
//            ProjectBackoutBorrowPrize backPrize = new ProjectBackoutBorrowPrize();
//            backPrize.setProjectId(project.getProjectId());
//            backPrize.setUserId(project.getBorrowUserId());
//            backPrize.setPrizeId(project.getPrizeId());
//            backPrize.setCreateTime(new Date());
//            projectBackoutBorrowPrizeMapperExt.insertSelective(backPrize);
//        }

        // 异步发送站内信、极光推送
        CompletableFuture.runAsync(() -> pushLetter(project.getBorrowUserId(), projectId, project.getFromSource(), getLetterTemplateKeyEnum(reasonTypeEnum), getJPushTemplateKeyEnum(reasonTypeEnum)));

        // 异步发送短信息
        CompletableFuture.runAsync(() -> sendSms(project.getBorrowUserId(), projectId, getSMSTemplateKeyEnum(reasonTypeEnum)));

        log.info(methodName + "-成功");
    }

    private ReturnProjectProcessSchemeEnum getReturnProjectProcessSchemeEnum(ReturnProjectReasonTypeEnum reasonTypeEnum) {

        if (reasonTypeEnum == null) {
            return null;
        }

        switch (reasonTypeEnum) {
            case ADDRESS_LIST_FAIL:
                return ReturnProjectProcessSchemeEnum.OTHER_INFO;
            case IDENTITY_REAL_INFO_FAIL:
                return ReturnProjectProcessSchemeEnum.PERSONAL_INFO;
            case LOAN_INFO_FAIL:
                return ReturnProjectProcessSchemeEnum.OTHER_INFO;
            case PERSONAL_INFO_FAIL:
                return ReturnProjectProcessSchemeEnum.PERSONAL_INFO;
            case PROFESSION_INFO_FAIL:
                return ReturnProjectProcessSchemeEnum.PROFESSION_INFO;
            case BANK_INFO_FAIL:
                return ReturnProjectProcessSchemeEnum.OTHER_INFO;
            case OPERATOR_AUTH_FAIL:
                return ReturnProjectProcessSchemeEnum.OPERATOR_AUTH;
            case SOCIAL_SECURITY_FAIL:
                return ReturnProjectProcessSchemeEnum.SOCIAL_SECURITY_;
            case CREDIT_CARD_FAIL:
                return ReturnProjectProcessSchemeEnum.CREDIT_CARD_AUTH;
            case TAOBAO_FAIL:
            	return ReturnProjectProcessSchemeEnum.TAOBAO_AUTH;
            case OTHER_EXCEPTION:
                return ReturnProjectProcessSchemeEnum.OTHER_INFO;
            default:
                return ReturnProjectProcessSchemeEnum.OTHER_INFO;
        }
    }

    // 获取标的退回原因
    private String getReturnReason(ReturnProjectReasonTypeEnum reasonTypeEnum) {

        String returnReasonPrefix = "退回原因:";
        if (reasonTypeEnum == null) {
            return returnReasonPrefix;
        }

        switch (reasonTypeEnum) {
            case ADDRESS_LIST_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case IDENTITY_REAL_INFO_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case LOAN_INFO_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case PERSONAL_INFO_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case PROFESSION_INFO_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case BANK_INFO_FAIL:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            case OPERATOR_AUTH_FAIL:
                return returnReasonPrefix + OPERATOR_AUTH_FAIL_RETURN_REASION;
            case SOCIAL_SECURITY_FAIL:
                return returnReasonPrefix + SOCIAL_SECURITY_FAIL_RETURN_REASION;
            case CREDIT_CARD_FAIL:
                return returnReasonPrefix + CREDIT_CARD_FAIL_RETURN_REASION;
            case TAOBAO_FAIL:
                return returnReasonPrefix + TAOBAO_FAIL_RETURN_REASION;
            case OTHER_EXCEPTION:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
            default:
                return returnReasonPrefix + OTHER_EXCEPTION_RETURN_REASION;
        }

    }

    private String getTaobaoAuthErrorText(String userId){
        String authErrorMsg = redisTemplate.opsForValue().get(TAOBAO_AUTH_ERROR_MSG_REDIS_KEY + userId);
        if(StringUtils.isBlank(authErrorMsg)){
            return TAOBAO_AUTH_DEFAULT_ERROR_MSG;
        }else {
            return authErrorMsg;
        }
    }

    private MessageTemplateKeyEnum.JPushTemplateKeyEnum getJPushTemplateKeyEnum(ReturnProjectReasonTypeEnum reasonTypeEnum) {

        if (reasonTypeEnum == null) {
            return null;
        }

        switch (reasonTypeEnum) {
            case ADDRESS_LIST_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case IDENTITY_REAL_INFO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case LOAN_INFO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case PERSONAL_INFO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case PROFESSION_INFO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case BANK_INFO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            case OPERATOR_AUTH_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OPERATOR_OBTAIN_FAIL_RETURN_PROJECT;
            case SOCIAL_SECURITY_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_SOCIAL_SECURITY_OBTAIN_FAIL_RETURN_PROJECT;
            case CREDIT_CARD_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_CREDIT_CARD_OBTAIN_FAIL_RETURN_PROJECT;
            case TAOBAO_FAIL:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT;                
            case OTHER_EXCEPTION:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
            default:
                return MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_OTHER_EXCEPTION_RETURN_PROJECT;
        }

    }

    private MessageTemplateKeyEnum.LetterTemplateKeyEnum getLetterTemplateKeyEnum(ReturnProjectReasonTypeEnum reasonTypeEnum) {

        if (reasonTypeEnum == null) {
            return null;
        }

        switch (reasonTypeEnum) {
            case ADDRESS_LIST_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case IDENTITY_REAL_INFO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case LOAN_INFO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case PERSONAL_INFO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case PROFESSION_INFO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case BANK_INFO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            case OPERATOR_AUTH_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OPERATOR_OBTAIN_FAIL_RETURN_PROJECT;
            case SOCIAL_SECURITY_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_SOCIAL_SECURITY_OBTAIN_FAIL_RETURN_PROJECT;
            case CREDIT_CARD_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_CREDIT_CARD_OBTAIN_FAIL_RETURN_PROJECT;
            case TAOBAO_FAIL:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT;                
            case OTHER_EXCEPTION:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
            default:
                return MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_OTHER_EXCEPTION_RETURN_PROJECT;
        }

    }

    private SMSTemplateKeyEnum getSMSTemplateKeyEnum(ReturnProjectReasonTypeEnum reasonTypeEnum) {

        if (reasonTypeEnum == null) {
            return null;
        }

        switch (reasonTypeEnum) {
            case ADDRESS_LIST_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case IDENTITY_REAL_INFO_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case LOAN_INFO_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case PERSONAL_INFO_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case PROFESSION_INFO_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case BANK_INFO_FAIL:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            case OPERATOR_AUTH_FAIL:
                return SMSTemplateKeyEnum.SMS_OPERATOR_OBTAIN_FAIL_RETURN_PROJECT;
            case SOCIAL_SECURITY_FAIL:
                return SMSTemplateKeyEnum.SMS_SOCIAL_SECURITY_OBTAIN_FAIL_RETURN_PROJECT;
            case CREDIT_CARD_FAIL:
                return SMSTemplateKeyEnum.SMS_CREDIT_CARD_OBTAIN_FAIL_RETURN_PROJECT;
            case TAOBAO_FAIL:
                return SMSTemplateKeyEnum.SMS_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT;                
            case OTHER_EXCEPTION:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
            default:
                return SMSTemplateKeyEnum.SMS_OTHER_EXCEPTION_RETURN_PROJECT;
        }

    }

    public void pushLetter(String userId, Long projectId, Byte fromSource, MessageTemplateKeyEnum.LetterTemplateKeyEnum letterTemplateKeyEnum, MessageTemplateKeyEnum.JPushTemplateKeyEnum jPushTemplateKeyEnum) {

        if (StringUtils.isEmpty(userId) || projectId == null || letterTemplateKeyEnum == null || jPushTemplateKeyEnum == null) {
            log.error("退回标的, 发送站内信、极光推送请求-失败, userId/projectId/letterTemplateKeyEnum/jPushTemplateKeyEnum非空");
            return;
        }

        String methodName = "退回标的，发送站内信、极光推送请求, userId:" + userId + ", projectId:" + projectId + ", letterTemplateKeyEnum:" + letterTemplateKeyEnum.getDesc() + ", jPushTemplateKeyEnum:" + jPushTemplateKeyEnum.getDesc();
        try {
            //极光推送+通知
            UserLetterRequestDTO userLetterRequestDTO = new UserLetterRequestDTO();
            if (fromSource != null && ProjectFromSourceEnum.APP.getType().equals(fromSource)) {
                userLetterRequestDTO.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH);
            } else {
                userLetterRequestDTO.setUserLetterTypeEnum(UserLetterTypeEnum.ONLY_LETTER);
            }

            //退回枚举
            userLetterRequestDTO.setLetterTemplateEnum(letterTemplateKeyEnum);
            //退回枚举
            userLetterRequestDTO.setJpushTemplateKeyEnum(jPushTemplateKeyEnum);

            // 按钮列表  钱小二、借款详情
            AppButtonDTO appButtonDTO1 = new AppButtonDTO();
            appButtonDTO1.setButtonType(AppButtonDTO.ButtonTypeEnum.MONEY_2);
            appButtonDTO1.setLabel(AppButtonDTO.ButtonTypeEnum.MONEY_2.getDesc());

            AppButtonDTO appButtonDTO2 = new AppButtonDTO();
            appButtonDTO2.setButtonType(AppButtonDTO.ButtonTypeEnum.VIEW_LOAN);
            appButtonDTO2.setLabel(AppButtonDTO.ButtonTypeEnum.VIEW_LOAN.getDesc());
            Map<String, Object> params = new HashMap<>();
            params.put("ProjectId", projectId);
            params.put("LoadServerUrl", h5BorrowDetailUrl + projectId);
            appButtonDTO2.setParams(params);

            List<AppButtonDTO> appButtonDTOS = new ArrayList<>();
            appButtonDTOS.add(appButtonDTO1);
            appButtonDTOS.add(appButtonDTO2);

            userLetterRequestDTO.setProjectId(projectId);
            userLetterRequestDTO.setToUserId(userId);
            userLetterRequestDTO.setLetterButtonList(appButtonDTOS);
            log.info(methodName+"参数判断");
            if(MessageTemplateKeyEnum.LetterTemplateKeyEnum.LETTER_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT.equals(letterTemplateKeyEnum)
                    ||MessageTemplateKeyEnum.JPushTemplateKeyEnum.JPUSH_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT.equals(jPushTemplateKeyEnum)){
                List<Object> paramList=new ArrayList<>(1);
                paramList.add(getTaobaoAuthErrorText(userId));
                userLetterRequestDTO.setLetterTemplateParamList(paramList);
                userLetterRequestDTO.setJpushTemplateParamList(paramList);
                log.info("添加消费借原因参数");
            }
            log.info(methodName + "-请求参数:{}", JSON.toJSONString(userLetterRequestDTO));
            userLetterDubboService.pushLetter(userLetterRequestDTO);
            log.info(methodName + "-成功");
        } catch (Exception e) {
            log.error(methodName + "-失败", e);
        }
    }

    public void sendSms(String userId, Long projectId, SMSTemplateKeyEnum templateKeyEnum) {

        if (StringUtils.isEmpty(userId) || projectId == null || templateKeyEnum == null) {
            log.error("退回标的, 发送短信请求-失败, userId/projectId/templateKeyEnum非空");
            return;
        }

        String methodName = "退回标的, 发送短信请求, userId:" + userId + ", projectId:" + projectId + ", templateKeyEnum:" + templateKeyEnum.getDesc();

        List<Object> paramList = null;
        if(SMSTemplateKeyEnum.SMS_TAOBAO_OBTAIN_FAIL_RETURN_PROJECT.equals(templateKeyEnum)){
            paramList = new ArrayList<>(1);
            paramList.add(getTaobaoAuthErrorText(userId));
        }

        //发送短信服务
        try {
            sendSmsDubboService.sendSmsByUserId(userId, templateKeyEnum.getKey(), paramList);
            log.info(methodName + "-成功");
        } catch (Exception e) {
            log.error(methodName + "-失败", e);
        }
    }

}
